package com.web.exiaodao.business.task;

import com.web.exiaodao.business.constant.JConstant;
import com.web.exiaodao.business.entity.Order;
import com.web.exiaodao.business.service.FestivalRemindService;
import com.web.exiaodao.remote.service.ApiConfigurationTableService;
import com.web.exiaodao.remote.service.ApiOrderService;
import com.web.exiaodao.remote.service.ApiShopCarService;
import com.web.exiaodao.remote.service.ApiWalletTradeRecordService;
import com.web.exiaodao.remote.vo.ConfigurationTableVo;
import com.web.webstart.base.constant.XaConstant;
import com.web.webstart.base.exception.BusinessException;
import com.web.webstart.base.service.impl.BaseService;
import com.web.webstart.base.util.DateUtils;
import com.web.webstart.base.util.Identities;
import com.web.webstart.base.util.SqlResultUtil;
import com.web.webstart.base.util.XaUtil;
import com.wxpay.PayReqRefundQueryData;
import com.wxpay.PayService;
import com.wxpay.common.Signature;
import com.wxpay.common.XMLParser;
import com.wxpay.config.WxpayConfig;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author duandazhi
 * @ClassName: SystemScheduled
 * @Description:
 * @date 2016/10/31 下午1:19
 */
@Component("FestivalRemindTask")
public class SystemScheduled extends BaseService {

    Logger log = Logger.getLogger(SystemScheduled.class);

    @Autowired
    private FestivalRemindService festivalRemindService;
    @Autowired
    private ApiOrderService orderService;
    @Autowired
    private ApiShopCarService shopCarService;
    @Autowired
    private ApiConfigurationTableService configurationTableService;
    @Autowired
    private ApiWalletTradeRecordService walletTradeRecordService;

    /**
     * 节日提醒的Task
     */
    @Scheduled(cron = "0 0 10 * * ?")    //每天的10点触发
    //  */1 * * * * ? 每隔1s执行一次
    //  0 0 3 * * ? 每天3点执行一次
    public void run() {
        try {
            log.info("定时器-节日提醒的Task-开始");
            //当天需要提醒的全部进行提醒
            festivalRemindService.queryFestivalRemind();
            log.info("定时器-节日提醒的Task-结束");
        } catch (Exception e) {
            log.error(e);
        }
    }

    /**
     * 库存改变的Task  使用event pro_backstock
     */
//    @Scheduled(cron = "*/600 * * * * ?")    //600s执行一次
//    //  */1 * * * * ? 每隔1s执行一次
//    //  0 0 3 * * ? 每天3点执行一次
//    public void runInventory() {
//        try {
//            log.info("定时器-库存处理的Task-开始");
//            String sql = "call pro_backstock()";
//            this.queryCall(sql, null);
//            log.info("定时器-库存处理的Task-结束");
//        } catch (Exception e) {
//            log.error(e);
//        }
//    }

    /**
     * 清除无效的购物车商品
     */
    @Scheduled(cron = "0 0 2 * * ?")    //每天2点执行
    //  */1 * * * * ? 每隔1s执行一次
    //  0 0 3 * * ? 每天3点执行一次
    public void runInventory() {
        try {
            log.info("定时器-清楚无效的购物车商品Task-开始");
            shopCarService.deleteInvalidCar();
            log.info("定时器-清楚无效的购物车商品Task-结束");
        } catch (Exception e) {
            log.error("清除无效的购物车商品fail" + e);
        }
    }

    /**
     * 定时查询微信退款状态
     *
     * @throws Exception
     */
    @Scheduled(cron = "0 0/10 * * * ?") //每10min
    public void refueAccount() throws Exception {
        try {
            log.info("定时查询微信退款状态开始!");
            String sql = "select o.order_no,o.refu_order_no from tb_xa_order o inner join tb_xa_returnshoprecord rs on o.order_no=rs.order_no where o.refund_status=" + JConstant.OrderRefundStatus.REFUNDING + " and o.payment_kind= " + JConstant.PayType.WXPAY;
            List<Object[]> objs = this.query(sql, null, null);
            if (XaUtil.isNotEmpty(objs) && objs.size() > 0) {
                for (Object[] obj : objs) {
                    String nonce_str = Identities.generateRandomCharAndNumber(16);
                    PayReqRefundQueryData data = new PayReqRefundQueryData();
                    data.setAppid(WxpayConfig.getAppID());
                    data.setMch_id(WxpayConfig.getMchID());
                    data.setNonce_str(nonce_str);
                    data.setOut_trade_no((String) obj[0]);
                    data.setSign(Signature.getSign(data));
                    String str = PayService.refundQuery(data);
                    Map<String, Object> map = XMLParser.getMapFromXML(str);
                    log.info("返回的Map结果集：" + map);
                    log.info("result_code：" + map.get("result_code"));
                    log.info("return_code：" + map.get("return_code"));
                    log.info("refund_status_0：" + map.get("refund_status_0"));
                    //退款成功
                    if ("SUCCESS".equals(map.get("result_code")) && "SUCCESS".equals(map.get("return_code"))) {
                        if ("SUCCESS".equals(map.get("refund_status_0"))) {    //退款成功
                            orderService.modifyOrderRefund((String) obj[1], JConstant.OrderRefundStatus.REFUND_SUCCESS, JConstant.PayType.WXPAY);
                        } else if ("FAIL".equals(map.get("refund_status_0"))) {    //退款失败
                            orderService.modifyOrderRefund((String) obj[1], JConstant.OrderRefundStatus.REFUND_FAIL, JConstant.PayType.WXPAY);
                        } else if ("NOTSURE".equals(map.get("refund_status_0"))) {    //需要商户原退款单号重新发起
                            log.info("不确定结果重新发起查询");
                            String nonce_str1 = Identities.generateRandomCharAndNumber(16);
                            PayReqRefundQueryData data1 = new PayReqRefundQueryData();
                            data1.setAppid(WxpayConfig.getAppID());
                            data1.setMch_id(WxpayConfig.getMchID());
                            data1.setNonce_str(nonce_str1);
                            data1.setOut_refund_no((String) obj[1]);
                            data1.setSign(Signature.getSign(data));
                            String str1 = PayService.refundQuery(data);
                            Map<String, Object> map1 = XMLParser.getMapFromXML(str1);
                            if ("SUCCESS".equals(map1.get("result_code")) && "SUCCESS".equals(map1.get("return_code"))) {
                                if ("SUCCESS".equals(map1.get("refund_status_0"))) {    //退款成功
                                    orderService.modifyOrderRefund((String) obj[1], JConstant.OrderRefundStatus.REFUND_SUCCESS, JConstant.PayType.WXPAY);
                                } else if ("FAIL".equals(map1.get("refund_status_0"))) {    //退款失败
                                    orderService.modifyOrderRefund((String) obj[1], JConstant.OrderRefundStatus.REFUND_FAIL, JConstant.PayType.WXPAY);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("定时查询微信退款状态出错" + e);
        }
    }

    /**
     * 自动收货 超过15天 自动收货
     *
     * @throws Exception
     */
    @Scheduled(cron = "0 0 3 * * ?")//每天3点执行
    public void autoRevice() throws Exception {
        log.info("自动收货!");
        String sql = "";
        try {
            //付款15天后自动收货
            sql = "update tb_xa_order o set o.order_state=" + JConstant.OrderStatus.UN_COMMENT + ",o.order_receiving_datetime= " + DateUtils.getToDayStr() + " where o.order_state=" + JConstant.OrderStatus.UN_CONSIGNEE + " and date_add(o.order_deliver_goods_date_time,interval 15 day) < now()";
            this.update(sql);
        } catch (Exception e) {
            log.error("自动收货、定时任务出错!" + e + "\n" + sql);
        }
    }

    /**
     * 自动评价、自动订单完成 超过8天
     * @throws Exception
     */
    @Scheduled(cron = "0 0 1 * * ?")//每天1点执行
    public void autoComment() throws Exception {
        log.info("自动评价、自动订单完成!");
        String sql = "";
        try {
            //付款8天 自动完成订单
             sql = "update tb_xa_order o set o.order_state=" + JConstant.OrderStatus.SUCCES_TRADE + ",o.order_sucess_date_time= " + DateUtils.getToDayStr() + " where o.order_state=" + JConstant.OrderStatus.UN_COMMENT + " and date_add(o.order_receiving_datetime,interval 8 day) < now() ";
            this.update(sql);
        } catch (Exception e) {
            log.error("默认评价、定时任务出错!" + e + "\nSQL:" + sql);
        }
    }

    /**
     * 计算佣金收益 超过15天 计算佣金收益
     * <p>
     * 每笔订单都完成后的15天都会计算推荐自己注册的这个人获取的收益
     * 收益目前支持二级
     *
     * @throws Exception
     */
    @Scheduled(cron = "0 0 4 * * ?")//每天4点执行
    //@Scheduled(cron = "*/600 * * * * ?")    //600s执行一次
    public void autoCalculateEarnings() throws Exception {
        log.info("计算佣金收益!");
        try {
            int days = 1;//默认15天
            //1:获取所有的订单完成时间>=15天并且没有计算过首页的订单
            //2:获取一级分销和二级分销的收益比例：订单支付金额*收益比例
            //3:获取该订单对应的一级分销人和二级分销的人
            //4:收益表写入收益记录
            ConfigurationTableVo configurationTableVo = configurationTableService.findLastOne().getObject();
            if (configurationTableVo == null || configurationTableVo.getDistribution1Rate() == null || configurationTableVo.getDistribution2Rate() == null) {
                throw new BusinessException(XaConstant.Message.object_not_config);
            }
            String orderSql = "SELECT user_id, order_no, order_total_pirce FROM tb_xa_order orders WHERE order_state = 4 AND order_type != 2 AND date_add(order_sucess_date_time,interval "+days+" day) <= now() AND orders.order_no NOT IN (SELECT DISTINCT(trade_order_no) FROM tb_xa_wallettraderecord WHERE trade_type = 4) ;";
            List<Object[]> objs = this.queryCall(orderSql, null);
            List<Order> orders = new ArrayList<>();
            for (int i = 0; objs != null && i < objs.size(); ++i) {
                Order order = new Order();
                orders.add(order);
                Object[] obj = objs.get(i);
                order.setUserId(SqlResultUtil.getSqlResultLong(obj[0]));
                order.setOrderNo(SqlResultUtil.getSqlResultString(obj[1]));
                order.setOrderTotalPirce(SqlResultUtil.getSqlResultDouble(obj[2]));

                walletTradeRecordService.autoCalculateEarnings(order, configurationTableVo);
            }
            log.info("计算佣金收益 sucess!");
        } catch (Exception e) {
            log.error("计算佣金收益出错!" + e);
        }
    }
}
